`include "defines.v"
module bpu(
  input  clk  ,
  input  rst_n,

  input  [`VADDR_W-1:0] npc,
  input  [`BRU_MSG_W-1:0] bru_message,

  output     reg        predict_valid,
  output [`VADDR_W-1:0] predict_pc   
);
`ifdef ENABLE_BPU
wire bht_taken;
reg [`VADDR_W-1:0] gen_pc;

always@(posedge clk or negedge rst_n)
  if(~rst_n)
    gen_pc <= 'd0;
  else 
    gen_pc <= npc;  

wire btb_hit;
wire [`VADDR_W-1:0] btb_pre_pc;


always@(*)begin
  if(btb_hit & bht_taken)
    predict_valid = 1'b1;
  else 
    predict_valid = 1'b0;
end

assign predict_pc    = btb_pre_pc ;

btb BTB(
  .clk   (clk  ) ,
  .rst_n (rst_n) ,
  // 查询路径
  .pc_i         (npc)        ,
  .hit_o        (btb_hit)    ,
  .predict_pc_o (btb_pre_pc) ,
  // 更新路径
  .redict_i      (bru_message[`BRU_MSG_W-1] & bru_message[`BRU_MSG_W-2]),
  .type_i        (bru_message[`BRU_MSG_W-3:`BRU_MSG_W-4]),
  .btb_pc_i      (bru_message[`VADDR_W*2-1:`VADDR_W]),
  .btb_jump_pc_i (bru_message[`VADDR_W-1:0])
);

// 1        1         4    
// {valid_i,redict_valid,mode,pc,redict_pc};
bht#(
  .PHT_DEPTH(1024)
)BHT(
  .clk          (clk  ),
  .rst_n        (rst_n),
  .gen_bht_pc_i (gen_pc),
  .taken_o      (bht_taken),

  .update_valid_i     (bru_message[`BRU_MSG_W-1]),
  .update_redict_i    (bru_message[`BRU_MSG_W-2]),
  .update_redict_pc_i (bru_message[`VADDR_W-1:0])
);


// instrScan InstrScan(
//   .instr ( icache_ibf_instr ),
//   .insrtScan_ras_Call_o ( insrtScan_ras_Call ),
//   .insrtScan_ras_Ret_o  ( insrtScan_ras_Ret  )
// );

// ras RAS(
//   .clk   ( clk   ),
//   .rst_n ( rst_n ),
//   .valid ( icache_ibf_data_valid && ibf_icache_data_ready),
//   .isCall( insrtScan_ras_Call ),
//   .isRet ( insrtScan_ras_Ret  ),
//   .gen_ras_pc_i( icache_ibf_vaddr ),
//   .taken_o           ( ras_ifu_valid ),
//   .ras_gen_jump_pc_o ( ras_ifu_addr  )
// );
// assign internaFlush = ras_ifu_valid;

`else
  assign predict_valid = 'd0;
  assign predict_pc    = 'd0;
`endif

endmodule
